package com.example.micro.netty.server.tcpnetty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;

/**
 * 1.我们自定义一个Handler 需要继承 netty规定的某个HandlerAdapter（Handler适配器）
 * 2.这时我们自定义一个Handler，才能称为一个Handler
 */
public class TcpNettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 读取数据事件（这里我们可以读取客户端发送的消息）
     *
     * @param ctx 上下文对象，含有 管道pipeline（可以处理很多handler），通道channel，连接地址
     * @param msg 就是客户端发送的数据，默认Object
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        String str = buf.toString(CharsetUtil.UTF_8);
        if (str.length() < 4) {
            Thread.sleep(5000);
            System.out.println("aaa");
            return;
        }
        System.out.println("客户端发送的消息是：" + buf.toString(CharsetUtil.UTF_8));

        //此处模拟一个耗时任务，将这个耗时任务扔进taskQueue中，等待执行
        ctx.channel().eventLoop().execute(() -> {
            try {
                System.out.println("thread任务线程情况：" + Thread.currentThread().getId());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        //此处添加一个定时任务，每5秒执行一次，是放在scheduleTaskQueue队列中的
        ctx.channel().eventLoop().schedule(() -> {
            System.out.println("定时任务，thread任务线程id：" + Thread.currentThread().getId());
        }, 5, TimeUnit.SECONDS);

        System.out.println("read任务线程情况：" + Thread.currentThread().getId());

//        super.channelRead(ctx, msg);
        /**
        System.out.println("server ctx = " + ctx);
        System.out.println("看看channel和pipeline的关系：");
        Channel channel = ctx.channel();
        ChannelPipeline pipeline = ctx.pipeline();//本质是一个双向链表，涉及到出栈入栈


        //将 msg 转成一个 ByteBuf
        //ByteBuf 是 Netty 提供的，并非 nio 原生的 ByteBuffer
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("客户端发送的消息是：" + buf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址是：" + ctx.channel().remoteAddress());
         **/
    }

    /**
     * 数据读取完毕
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//        super.channelReadComplete(ctx);
        //writeAndFlush 是 write + flush
        //将数据写入到缓存，并刷新（相当于把数据刷入到管道中，发出去）
        //一般来说，我们需要对这个发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello,客户端～", CharsetUtil.UTF_8));

    }

    /**
     * 处理异常，一般需要关闭通道
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        super.exceptionCaught(ctx, cause);
        ctx.close();
    }

}
